const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');

const sourceDir = 'src/components'; // 源文件目录

/**
 * 封装一个异步方法进行文件拷贝
 * @param {*} sourceFile 拷贝的文件
 * @param {*} targetFile 被拷贝到的目录
 * @returns Promise
 */
const copyAsyncFile = (sourceFile, targetFile) => {
  return new Promise((resolve, reject)=> {
    fs.copyFile(sourceFile, targetFile, (err) => {
      if (err) {
        reject('文件拷贝失败')
      } else {
        resolve()
      }
    });
  })
}

/**
 * 创建一个components
 */
const mkdirDistComponents = async () => {
  const directoryPath = 'dist/components';
  let res = await folderHasFile(directoryPath)
  if(res == 0){
    await mkdirFolder(directoryPath);
  }
}

/**
 * 创建目录
 */
const mkdirFolder = (path) => {
  return new Promise((resolve, reject)=> {
    fs.mkdir(path, { recursive: true }, (err) => {
      if (err) {
        reject('目录创建失败')
      } else {
        resolve()
      }
    });
  })
}

/**
 * 创建文件
 */
const mkdirFile = (path) => {
  return new Promise((resolve, reject)=> {
    fs.writeFile(path, '', (err) => {
      if (err) {
        reject('文件创建失败')
      } else {
        resolve('文件创建成功')
      }
    });
  })
}

/**
 * 判断一个目录下是否有文件
 */
const folderHasFile = (directoryPath) => {
  return new Promise((resolve, reject)=> {
    fs.readdir(directoryPath, (err, files) => {
      if (err) {
        resolve(0)
      } else {
        resolve(files.length)
      }
    });
  })
}

/**
 * 创建对应的components目录
 */
const mkdirComponentFolder = async (parentName) => {
  let fileLen = await folderHasFile(`dist/components/${parentName}`);
  if(fileLen != 0){ return }

  // 创建三个对应的文件
  await mkdirFolder(`dist/components/${parentName}/design-time`);
  await mkdirFolder(`dist/components/${parentName}/props-panel`);
  await mkdirFolder(`dist/components/${parentName}/runtime`)

}

// 获取源文件目录下的所有组件文件夹
const componentDirs = fs.readdirSync(sourceDir);

// 遍历组件文件夹
componentDirs.forEach(componentDir => {
  const designTimeDir = path.join(sourceDir, componentDir, 'design-time');
  const runTimeDir = path.join(sourceDir, componentDir, 'runtime');
  const propsPanelDir = path.join(sourceDir, componentDir, 'props-panel');

  const buildDesignFn = (argPath, type) => {
    const buildFiles = fs.readdirSync(argPath);
    buildFiles.forEach(file => {
      // 此处打包需要忽略被使用的文件夹，只对vue文件打包 [不然会报一个错误，说对目录打包报错，由于下面的打包命令仅对vue文件生效]
      if(!file.endsWith('.vue')) return
      let parentName = path.basename(componentDir, path.extname(componentDir));
      const filePath = path.join(argPath, file);
      const fileName = path.basename(file, path.extname(file));
      // 最终前缀目录，用于区分每个组件
      const libName = `${parentName}_${type}_${fileName}`

      // 执行打包命令
      // `npx vue-cli-service build --target lib --name ${libName} --entry ${filePath}`
      const command = `npx vue-cli-service build --target lib --name ${libName} --entry ${filePath}`;
      console.log(`正在打包${libName}模块`);
      const child = exec(command, { cwd: path.resolve(__dirname) });

      child.stdout.on('data', (data) => {
        console.log(data);
      });

      child.stderr.on('data', (data) => {
        console.error(data);
      });

      child.on('error', (error) => {
        console.error(`Error while building ${filePath}: ${error.message}`);
      });

      child.on('exit', async (code) => {
        if (code === 0) {
          // 创建dist/components目录
          await mkdirDistComponents();

          // 创建相对应的目录结构
          await mkdirComponentFolder(parentName)

          // 插入打包文件到新目录下
          let sourceFile = `dist/${libName}.umd.min.js`
          let targetUrl = filePath.split('\\');
          targetUrl.pop();
          targetUrl.shift();
          let targetFile = `dist/${targetUrl.join('/')}/${fileName}.js`;
          await copyAsyncFile(sourceFile, targetFile);

          // 拷贝对应的component.json文件到对应的目录下
          if(type == 'runtime'){
            let splitUtl = filePath.split('\\');
            splitUtl.pop();
            splitUtl.pop();
            let sourceJsonFile = `dist/${splitUtl.join('/')}/component.json`;
            splitUtl.shift();
            let targetJsonFile = `dist/${splitUtl.join('/')}/component.json`;
            await copyAsyncFile(sourceJsonFile, targetJsonFile);
          }

          // 删除打包vue文件衍生的多余的js文件
          // await removeBuildVueComponentVueJs(libName)
        } else {
          console.error(`${filePath}: 打包构建失败`);
        }
      });
    });
  }

  // 获取design-time目录下的所有文件
  buildDesignFn(designTimeDir, 'design-time');
  buildDesignFn(runTimeDir, 'runtime');
  buildDesignFn(propsPanelDir, 'props-panel');

});
